package com.lcn.netty.handler;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.lcn.enums.MsgTypeEnum;
import com.lcn.netty.manager.UserChannelSession;
import com.lcn.netty.mq.MessagePublisher;
import com.lcn.netty.utils.JedisPoolUtils;
import com.lcn.netty.utils.ZookeeperRegister;
import com.lcn.pojo.netty.ChatMsg;
import com.lcn.pojo.netty.DataContent;
import com.lcn.pojo.netty.NettyServerNode;
import com.lcn.utils.JsonUtils;
import com.lcn.utils.LocalDateUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 自定义助手类(单体)
 * TextWebSocketFrame是数据载体
 */
@Slf4j
public class ChatHandlerSingle extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    // 用于记录和管理所有客户端的channel组
    public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 获取客户端传输的消息
        String content = msg.text();
        DataContent dataContent = JsonUtils.jsonToPojo(content, DataContent.class);
        ChatMsg chatMsg = dataContent.getChatMsg();
        Integer msgType = chatMsg.getMsgType(); // 消息类型
        String msgText = chatMsg.getMsg(); // 消息正文
        String senderId = chatMsg.getSenderId();
        String receiverId = chatMsg.getReceiverId(); // 接受者的用户id
        // 获取channel
        Channel currentChannel = ctx.channel();
        String currentChannelId = currentChannel.id().asLongText();
        chatMsg.setChatTime(LocalDateTime.now());
        String iid = IdWorker.getIdStr(); // 雪花算法设置主键
        chatMsg.setMsgId(iid);
        // 第一次连接要做的操作
        if (msgType == MsgTypeEnum.CONNECT_INIT.type) {
            // 保存用户与频道的联系
            UserChannelSession.putMultiSession(senderId, currentChannel);
            UserChannelSession.putUserChannelIdMap(currentChannelId, senderId);

            // 第一次连接累加在线人数
            NettyServerNode nettyServerNode = dataContent.getServerNode();
            ZookeeperRegister.incrementOnlineCounts(nettyServerNode);

            // 方便断开连接时获取node
            Jedis jedis = JedisPoolUtils.getJedis();
            jedis.set(senderId, JsonUtils.objectToJson(nettyServerNode));

        } else if (msgType == MsgTypeEnum.WORDS.type // 发送文字/表情
                || msgType == MsgTypeEnum.IMAGE.type // 图片
                || msgType == MsgTypeEnum.VIDEO.type) {  // 视频
            // 获取接受者的所有频道
            List<Channel> channelList = UserChannelSession.getMultiSession(receiverId);
            if (channelList == null || channelList.size() == 0) {
                // 离线
                chatMsg.setIsReceiverOnLine(false);
            } else {
                // 在线
                chatMsg.setIsReceiverOnLine(true);
                sendChatMsg(channelList, dataContent, chatMsg);
            }
            // 发送MQ消息，持久化消息（初始化时不需要）
            MessagePublisher.sendMsgToSave(chatMsg);
        }

        // 同步其他端的消息
        List<Channel> myOtherChannel = UserChannelSession.getMyOtherChannel(senderId, currentChannelId);
        sendChatMsg(myOtherChannel, dataContent, chatMsg);


//        currentChannel.writeAndFlush(new TextWebSocketFrame(currentChannelId));
        UserChannelSession.outputMulti();
    }

    /**
     * 发送聊天消息
     */
    private void sendChatMsg(List<Channel> channels, DataContent dataContent, ChatMsg chatMsg) {
        if (channels == null || channels.size() == 0) {
            return;
        }
        for (Channel channel : channels) {
            Channel findChannel = clients.find(channel.id());
            if (findChannel != null) {
                dataContent.setChatTime(LocalDateUtils.format(chatMsg.getChatTime(), LocalDateUtils.DATETIME_PATTERN_2));
                dataContent.setChatMsg(chatMsg);
                // 发送消息
                channel.writeAndFlush(new TextWebSocketFrame(JsonUtils.objectToJson(dataContent)));
            }
        }
    }

    /**
     * 建立连接
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String longText = channel.id().asLongText();
        System.out.println("客户端建立连接，长连接名为" + longText);
        clients.add(channel);
    }

    /**
     * 销毁连接
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String longText = channel.id().asLongText();
        clients.remove(channel);
        String userId = UserChannelSession.getUserIdByChannelId(longText);
        UserChannelSession.removeMultiSession(userId, longText);
        Jedis jedis = JedisPoolUtils.getJedis();
        String json = jedis.get(userId);
        NettyServerNode nettyServerNode = JsonUtils.jsonToPojo(json, NettyServerNode.class);
        ZookeeperRegister.decrementOnlineCounts(nettyServerNode);
    }

//    @Override
//    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        Channel channel = ctx.channel();
//        String longText = channel.id().asLongText();
//        clients.remove(channel);
//        String userId = UserChannelSession.getUserIdByChannelId(longText);
//        UserChannelSession.removeMultiSession(userId, longText);
//
//        Jedis jedis = JedisPoolUtils.getJedis();
//        String json = jedis.get(userId);
//        if (StringUtils.isNotBlank(json)) {
//            System.out.println("=============异常连接增加在线人数");
//            NettyServerNode nettyServerNode = JsonUtils.jsonToPojo(json, NettyServerNode.class);
//            ZookeeperRegister.decrementOnlineCounts(nettyServerNode);
//        } else {
//            System.out.println("=============异常json为空");
//        }
//    }


}
